package com.and.rsspect;

import java.util.List;

import org.xmlpull.v1.XmlPullParser;

/**
 * che.heng
 */
abstract public class AbsRRSReader {

	protected static final String namespaceURI = "http://www.w3.org/2005/Atom";

	/**
	 * @param reader
	 * @return RSS
	 * @throws Exception
	 */
	abstract public RSS readRSS(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 获取元素的属性
	 * 
	 * @param reader
	 * @return List
	 * @throws Exception
	 */
	abstract protected List<Attribute> getAttributes(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 获取扩展元素
	 * 
	 * @param reader
	 * @param extensions
	 * @param elementName
	 * @return
	 * @throws Exception
	 */
	abstract protected List<Extension> readExtension(XmlPullParser reader,
			List<Extension> extensions, String elementName) throws Exception;

	/**
	 * 
	 * 解析Author标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Author readAuthor(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析Category标签
	 * 
	 * @param reader
	 * @param categories
	 * @return
	 * @throws Exception
	 */
	abstract protected List<Category> readCategory(XmlPullParser reader,
			List<Category> categories) throws Exception;

	/**
	 * 
	 * 解析Channel以及其下的所有元素
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Channel readChannel(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Cloud标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Cloud readCloud(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析Comments标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Comments readComments(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Copyright标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Copyright readCopyright(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Description标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Description readDescription(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Doc标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Docs readDocs(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析Enclosure标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Enclosure readEnclosure(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Generator标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Generator readGenerator(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析GUID标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected GUID readGUID(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析Image标签下的Height标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Height readHeight(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析Image标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Image readImage(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析Item标签及其下所有元素
	 * 
	 * @param reader
	 * @param items
	 * @return
	 * @throws Exception
	 */
	abstract protected List<Item> readItem(XmlPullParser reader,
			List<Item> items) throws Exception;

	/**
	 * 
	 * 解析Item标签及其下所有元素
	 * 
	 * @param parser
	 * @return
	 * @throws Exception
	 */
	abstract protected Item readItem(XmlPullParser parser) throws Exception;

	/**
	 * 
	 * 解析Language标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Language readLanguage(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析LastBuildDate标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected LastBuildDate readLastBuildDate(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Link标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Link readLink(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析ManagingEditor
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected ManagingEditor readManagingEditor(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析readName标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Name readName(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析PubDate标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected PubDate readPubDate(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Rating标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Rating readRating(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析SkipDays标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected SkipDays readSkipDays(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Day标签
	 * 
	 * @param reader
	 * @param days
	 * @return
	 * @throws Exception
	 */
	abstract protected List<Day> readDay(XmlPullParser reader, List<Day> days)
			throws Exception;

	/**
	 * 
	 * 解析SkipHours标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected SkipHours readSkipHours(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Hour标签
	 * 
	 * @param reader
	 * @param hours
	 * @return
	 * @throws Exception
	 */
	abstract protected List<Hour> readHour(XmlPullParser reader,
			List<Hour> hours) throws Exception;

	/**
	 * 
	 * 解析Source标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Source readSource(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析TextInput标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected TextInput readTextInput(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Title标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Title readTitle(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析TTL标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected TTL readTTL(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析URL标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected URL readURL(XmlPullParser reader) throws Exception;

	/**
	 * 
	 * 解析WebMaster标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected WebMaster readWebMaster(XmlPullParser reader)
			throws Exception;

	/**
	 * 
	 * 解析Width标签
	 * 
	 * @param reader
	 * @return
	 * @throws Exception
	 */
	abstract protected Width readWidth(XmlPullParser reader) throws Exception;

	/**
	 * @param reader
	 * @param parentElement
	 * @return
	 * @throws Exception
	 */
	abstract protected String readEncodedHTML(XmlPullParser reader,
			String parentElement) throws Exception;

	protected boolean containsXHTML(XmlPullParser reader, String elementName) {
		if (reader.getNamespace().equals("http://www.w3.org/1999/xhtml")) {
			return true;
		}
		// if (elementName.indexOf(":") != -1) {
		// String ns =
		// reader.getNamespaceURI(elementName.substring(0,elementName.indexOf(":")));
		// return ns != null && ns.equals("http://www.w3.org/1999/xhtml");
		// }
		return false;
	}

	/**
	 * 
	 * @param reader
	 * @param elementName
	 * @param parentAttributes
	 * @return
	 * @throws Exception
	 */
	protected String readSubExtension(XmlPullParser reader, String elementName,
			List<Attribute> parentAttributes) throws Exception {

		StringBuffer xhtml = new StringBuffer("<" + elementName);

		List<Attribute> attributes = getAttributes(reader);
		// add the attributes
		if (attributes != null && attributes.size() > 0) {
			for (Attribute attr : attributes) {
				xhtml.append(" " + attr.getName() + "=\"" + attr.getValue()
						+ "\"");
			}
		}
		boolean openElementClosed = false;
		String elementNameStart = elementName;

		for (int eventType; (eventType = reader.getEventType()) != XmlPullParser.END_DOCUMENT; reader
				.next()) {
			boolean breakOut = false;
			switch (eventType) {

			case XmlPullParser.START_TAG:
				elementNameStart = reader.getName();
				if (!elementNameStart.equals(elementName)) {
					if (!openElementClosed) {
						openElementClosed = true;
						xhtml.append(">");
					}
					xhtml.append(readSubExtension(reader, elementNameStart,
							attributes));
				}
				break;

			case XmlPullParser.END_TAG:
				String elementNameEnd = reader.getName();
				if (elementNameEnd.equals(elementName)) {
					breakOut = true;
				}

				if (openElementClosed) {
					xhtml.append("</" + elementName + ">");
				} else {
					xhtml.append(" />");
				}

				break;

			// so far no parsers seem to be able to detect CDATA :(. Maybe a
			// not necessary?
			// case XMLStreamConstants.CDATA:
			// xhtml.append("<![CDATA[" + reader.getText() + "]]>");
			// break;

			default:
				// close the open element if we get here
				if (elementNameStart.equals(elementName)) {
					xhtml.append(" >");
					openElementClosed = true;
				}
				xhtml.append(reader.getText());
			}
			if (breakOut) {
				break;
			}
		}
		return xhtml.toString();
	}

	/**
	 * 
	 * @param reader
	 * @param parentElement
	 * @return
	 * @throws Exception
	 */
	protected String readXHTML(XmlPullParser reader, String parentElement)
			throws Exception {
		String parentNamespaceURI = namespaceURI;
		StringBuffer xhtml = new StringBuffer();
		String elementName = null;
		boolean justReadStart = false;

		for (int eventType; (eventType = reader.getEventType()) != XmlPullParser.END_DOCUMENT; reader
				.next()) {
			boolean breakOut = false;
			switch (eventType) {

			case XmlPullParser.START_TAG:
				elementName = reader.getName();
				// if we read 2 start elements in a row, we need to close the
				// first start element.
				if (justReadStart) {
					xhtml.append(">");
				}

				xhtml.append("<" + elementName);

				List<Attribute> attributes = getAttributes(reader);
				// add the attributes
				if (attributes != null && attributes.size() > 0) {
					for (Attribute attr : attributes) {
						String attrVal = attr.getValue();
						xhtml.append(" " + attr.getName() + "=\"" + attrVal
								+ "\"");
					}
				}
				justReadStart = true;

				break;

			case XmlPullParser.END_TAG:
				elementName = reader.getName();
				if ((elementName.equals(parentElement) && !namespaceURI
						.equals("http://www.w3.org/1999/xhtml"))
						|| (elementName.equals(parentElement) && parentNamespaceURI
								.equals("http://www.w3.org/1999/xhtml"))) {
					breakOut = true;
				} else {
					if (justReadStart) {
						xhtml.append(" />");
					} else {
						xhtml.append("</" + elementName + ">");
					}
					justReadStart = false;
				}
				break;

			// so far no parsers seem to be able to detect CDATA :(. Maybe a
			// not necessary?
			// case XMLStreamConstants.CDATA:
			// xhtml.append("<![CDATA[" + reader.getText() + "]]>");
			// break;

			default:
				if (justReadStart) {
					xhtml.append(">");
					justReadStart = false;
				}
				// escape the markup.
				String text = reader.getText();
				// if the feed we are reading has invalid escaping the text
				// will be null which results in a skipping of the malformed
				// character.
				if (text != null) {
					xhtml.append(text.replaceAll("&", "&amp;")
							.replaceAll("<", "&lt;").replaceAll(">", "&gt;"));
				}
			}
			if (breakOut) {
				break;
			}
		}
		return xhtml.toString();
	}

	/**
	 * 
	 * @param attributes
	 * @param attributeName
	 * @return
	 */
	protected Attribute getAttributeFromGroup(List<Attribute> attributes,
			String attributeName) {
		if (attributes != null) {
			for (Attribute current : attributes) {
				if (current.getName().equalsIgnoreCase(attributeName)) {
					return new Attribute(current);
				}
			}
		}
		return null;
	}

}
